package impl

import (
	"context"

	"github.com/infraboard/mcube/v2/exception"
	"github.com/infraboard/mcube/v2/ioc"
	"github.com/infraboard/mcube/v2/ioc/config/datasource"
	"gitlab.com/go-course-project/go17/vblog/apps/user"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

func init() {
	ioc.Controller().Registry(&UserServiceImpl{})
}

// int(10) -> (int)(10)
var _ user.Service = (*UserServiceImpl)(nil)

// 定义一个struct, 用于实现 UserService就是刚才定义的接口
// 怎么才能判断这个结构体没有实现这个接口
type UserServiceImpl struct {
	// 这个对象 就实现ioc Object接口, 他就能被放到ioc
	ioc.ObjectImpl
}

func (i *UserServiceImpl) Name() string {
	return user.AppName
}

// DescribeUser implements user.Service.
func (u *UserServiceImpl) DescribeUser(ctx context.Context, in *user.DescribeUserRequest) (*user.User, error) {
	query := datasource.DBFromCtx(ctx)
	switch in.DescribeBy {
	case user.DESCRIBE_BY_ID:
		query = query.Where("id = ?", in.Value)
	case user.DESCRIBE_BY_USERNAME:
		query = query.Where("username = ?", in.Value)
	}

	ins := &user.User{}
	if err := query.Take(ins).Error; err != nil {
		// 自定义异常
		if err == gorm.ErrRecordNotFound {
			return nil, exception.NewNotFound("user %s not found", in.Value)
		}
		return nil, err
	}
	return ins, nil
}

// Registry implements user.Service.
func (u *UserServiceImpl) Registry(ctx context.Context, in *user.RegistryRequest) (*user.User, error) {
	ins, err := user.New(in)
	if err != nil {
		return nil, err
	}

	// 明文密码保持到数据库，是不安全
	// 对称加密/非对称， 解密
	// 消息摘要, 无法还原
	// 怎么知道用户的密码 比对hash  123 -> (xxx)
	// md5 sha1/256/512, hmac, ...
	// 结果固定
	hashPass, err := bcrypt.GenerateFromPassword([]byte(in.Password), bcrypt.DefaultCost)
	if err != nil {
		return nil, err
	}
	ins.Password = string(hashPass)

	if err := datasource.DBFromCtx(ctx).Create(ins).Error; err != nil {
		return nil, err
	}

	// context.WithValue()

	// 无事务的模式
	// datasource.DB().Transaction(func(tx *gorm.DB) error {
	// 	ctx := datasource.WithTransactionCtx(ctx)
	// 	// 1.
	// 	svcA.Call(ctx)
	// 	// 2.
	// 	svcB.Call(ctx)
	// 	// 3.
	// 	svcC.Call(ctx)
	// })

	return ins, nil
}

// ResetPassword implements user.Service.
func (u *UserServiceImpl) ResetPassword(context.Context, *user.ResetPasswordRequest) error {
	panic("unimplemented")
}

// UnRegistry implements user.Service.
func (u *UserServiceImpl) UnRegistry(ctx context.Context, in *user.UnRegistryRequest) {
	// datasource.GetTransactionFromCtx(ctx)
	// datasource.DB()
	// datasource.DBFromCtx()
	panic("unimplemented")
}

// UpdatePassword implements user.Service.
func (u *UserServiceImpl) UpdatePassword(context.Context, *user.UpdatePasswordRequest) error {
	panic("unimplemented")
}

// UpdateProfile implements user.Service.
func (u *UserServiceImpl) UpdateProfile(context.Context, *user.UpdateProfileRequest) (*user.User, error) {
	panic("unimplemented")
}

// UpdateUserStatus implements user.Service.
func (u *UserServiceImpl) UpdateUserStatus(context.Context, *user.UpdateUserStatusRequest) (*user.User, error) {
	panic("unimplemented")
}
